package io.bdmc.core.dts;

import com.alibaba.fastjson2.JSONObject;
import io.bdmc.common.exception.CMSException;
import io.bdmc.common.utils.ByteUtil;
import io.bdmc.common.utils.Constant;
import io.bdmc.common.utils.StringUtils;
import io.bdmc.core.msp2000.DataParse;
import io.bdmc.core.udp.UdpClientSendData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.*;
import java.util.*;

@Component
@Slf4j
public class DtsDeviceUtil {

    @Autowired
    UdpClientSendData udpClient;

    /**
     * 通过ip地址读取dts配置
     *
     * @param ipaddr ip
     * @param port   端口
     * @return 读取结果
     */
    public boolean readDtsConfigFromDevice(String ipaddr, int port) {
        String msg = DtsDownCmd.buildReadConfigInfoMsg();
        String result = udpClient.sendTcpDTSData(ipaddr, port, msg);
        DtsFullData dts = DataParse.paserDtsHeadData(result);
        if (dts != null) {
            byte[] config = ByteUtil.HexToBytes(dts.bodyData);
            // 配置文件可以直接写入文件
            writeToConfig(config, ipaddr, "");
        }
        return true;
    }

    /**
     * 下发配置action
     *
     * @param ipaddr 设备ip
     * @param port   设备端口
     * @param config 配置文件读取的str
     * @return 是否下发成功
     */
    public boolean sendToDtsDevice(String ipaddr, int port, String config) {
        String configFile = ByteUtil.bytesToHex(config.getBytes());
        System.out.println(configFile);
        String msg = DtsDownCmd.buildSetConfigInfoMsg(configFile);
        String result = udpClient.sendTcpDTSData(ipaddr, port, msg);
        DtsFullData dts = DataParse.paserDtsHeadData(result);
        if (dts != null && dts.bodyData.equals("00")) {
            // 设置成功
            System.out.println("设置成功");
            return true;
        } else {
            System.out.println("设置失败");
            return false;
        }
    }

    /**
     * 获取原始曲线as和s
     *
     * @param ipaddr ip
     * @param port   端口
     * @param ch     通道号，从1开始
     * @return 2条曲线数据
     */
    public Map<String, Object> getOriginCurve(String ipaddr, int port, int ch) {
        ch -= 1;// 设备是从0开始
        String msg = DtsDownCmd.buildReadASSOriginalDataMsg(ch);
        String result = udpClient.sendTcpDTSData(ipaddr, port, msg);
        DtsFullData dts = DataParse.paserDtsHeadData(result);
        if (dts == null)
            return null;

        int ch1 = ByteUtil.HexToInt(dts.bodyData, 0, 2);
        if (ch1 != ch) {
            return null;
        }
        Map<String, Object> map = new HashMap<>(2);

        int count = (dts.bodyData.length() - 10) / 16;
        List<Double> asLt = new ArrayList<>();
        List<Double> sLt = new ArrayList<>();
        String temData = dts.bodyData.substring(10);
        for (int i = 0; i < count; i++) {
            String astmp = temData.substring(i * 8, 8 + i * 8);
            asLt.add(ByteUtil.HexToInt(astmp) / 1000000.0);
            String stmp = temData.substring(count * 8 + i * 8, count * 8 + i * 8 + 8);
            sLt.add(ByteUtil.HexToInt(stmp) / 1000000.0);
        }
        map.put("asLt", asLt);
        map.put("sLt", sLt);
        return map;
    }

    /**
     * 获取原始曲线as/s 比例曲线
     *
     * @param ipaddr ip
     * @param port   端口
     * @param ch     通道号，从1开始
     * @return 1条曲线数据
     */
    public List<Double> getOriginDividedCurve(String ipaddr, int port, int ch) {
        ch -= 1;// 设备是从0开始
        String msg = DtsDownCmd.buildReadASSDataMsg(ch);
        UdpClientSendData client = new UdpClientSendData();
        String result = client.sendTcpDTSData(ipaddr, port, msg);
        DtsFullData dts = DataParse.paserDtsHeadData(result);
        if (dts == null)
            return null;

        int ch1 = ByteUtil.HexToInt(dts.bodyData, 0, 2);
        if (ch1 != ch)
            return null;
        // int id = ByteUtil.HexToInt(dts.bodyData, 2, 10);
        int count = (dts.bodyData.length() - 10) / 4;
        List<Double> dividedList = new ArrayList<>();
        String temData = dts.bodyData.substring(10);
        for (int i = 0; i < count; i++) {
            String astmp = temData.substring(0, 4);
            temData = temData.substring(4);
            dividedList.add(ByteUtil.HexToInt(astmp) / 10000.0);
        }
        return dividedList;
    }

    /**
     * 获取原始曲线as/s
     *
     * @param ipaddr ip
     * @param port   端口
     * @param ch     通道号，从1开始
     * @return 2条曲线数据
     */
    public List<Double> getTempCurve(String ipaddr, int port, int ch) {
        ch -= 1;// 设备是从0开始
        String msg = DtsDownCmd.buildReadAllTemperatureMsg(ch);
        UdpClientSendData client = new UdpClientSendData();
        String result = client.sendTcpDTSData(ipaddr, port, msg);
        DtsFullData dts = DataParse.paserDtsHeadData(result);
        if (dts != null) {
            System.out.println(dts.bodyData);
            int ch1 = ByteUtil.HexToInt(dts.bodyData, 0, 2);
            if (ch1 != ch)
                return null;
            int count = (dts.bodyData.length() - 10) / 4;
            List<Double> tempList = new ArrayList<>();
            String temData = dts.bodyData.substring(10);
            for (int i = 0; i < count; i++) {
                String tmp = temData.substring(4 * i, 4 + i * 4);

                tempList.add(ByteUtil.HexToInt(tmp) / 10.0);
            }
            return tempList;
        }
        return null;
    }

    /**
     * 获取设备的温度
     * 
     * @param ipaddr     ip
     * @param devicePort 端口
     * @return 设备温度值
     */
    public double getDtsTemp(String ipaddr, Integer devicePort) {
        String msg = DtsDownCmd.buildReadTemperatureSensor();
        UdpClientSendData client = new UdpClientSendData();
        String result = client.sendTcpDTSData(ipaddr, devicePort, msg);
        DtsFullData dts = DataParse.paserDtsHeadData(result);
        double temp = 0d;
        if (dts != null) {
            System.out.println(dts.bodyData);
            temp = ByteUtil.HexToInt(dts.bodyData) / 10.0;
        }
        return temp;
    }

    /**
     * 设置温度曲线的修正开关 ，每个通道的修正开关
     * 
     * @param ipaddr      ip
     * @param devicePort  端口
     * @param channel     通道
     * @param fixedSwitch fixedSwitch = 1;//设置为1表示打开CH通道的修正开关，设置为0表示不修正温度曲线
     */
    public boolean setTemperatureCurveFixedSwitch(String ipaddr, int devicePort, int channel, int fixedSwitch) {
        channel -= 1;
        String msg = DtsDownCmd.buildSetTemperatureCurveFixedSwitch(channel, fixedSwitch);
        String result = udpClient.sendTcpDTSData(ipaddr, devicePort, msg);
        DtsFullData dts = DataParse.paserDtsHeadData(result);
        if (dts != null) {
            int responseCh = ByteUtil.HexToInt(dts.bodyData.substring(0, 2));
            int responseFixedSwitch = ByteUtil.HexToInt(dts.bodyData.substring(2, 4));
            System.out.println("应答" + responseCh + "," + responseFixedSwitch);
            // 成功
            return responseCh == channel && responseFixedSwitch == fixedSwitch;
        }
        return false;
    }

    /**
     * 读取温度曲线的修正开关量，1表示打开CH通道的修正开关，0表示不修正温度曲线
     * 
     * @param ipaddr     ip
     * @param devicePort 端口
     * @param channel    通道
     * @return fixedSwitch
     */
    public int getTemperatureCurveFixedSwitch(String ipaddr, int devicePort, int channel) {
        channel -= 1;
        String msg = DtsDownCmd.buildReadTemperatureCurveFixedSwitch(channel);
        String result = udpClient.sendTcpDTSData(ipaddr, devicePort, msg);
        DtsFullData dts = DataParse.paserDtsHeadData(result);
        if (dts != null) {
            int responseCh = ByteUtil.HexToInt(dts.bodyData.substring(0, 2));
            int responseFixedSwitch = ByteUtil.HexToInt(dts.bodyData.substring(2, 4));
            System.out.println("应答" + responseCh + "," + responseFixedSwitch);
            return responseFixedSwitch;
        }
        return -1;
    }

    /**
     * 执行一次温度曲线自动修正计算
     * 
     * @param ipaddr      ip
     * @param devicePort  端口
     * @param channel     通道
     * @param fixedSwitch 设置为1表示执行温度曲线自动修正计算，设置为0表示不操作。
     * @return 结果
     */
    public boolean setTemperatureCurveAutocorrection(String ipaddr, int devicePort, int channel, int fixedSwitch) {
        channel -= 1;
        String msg = DtsDownCmd.buildSetTemperatureCurveAutocorrection(channel, fixedSwitch);
        String result = udpClient.sendTcpDTSData(ipaddr, devicePort, msg);
        DtsFullData dts = DataParse.paserDtsHeadData(result);
        if (dts != null) {
            int responseCh = ByteUtil.HexToInt(dts.bodyData.substring(0, 2));
            int responseFixedSwitch = ByteUtil.HexToInt(dts.bodyData.substring(2, 4));
            System.out.println("应答" + responseCh + "," + responseFixedSwitch);
            // 成功
            return responseCh == channel && responseFixedSwitch == fixedSwitch;
        }
        return false;
    }

    /**
     * 将配置写到文件
     *
     * @param bs       字节
     * @param dtsIp    ip
     * @param fileName 默认文件名，不带路径，空字符串默认ip为文件名
     */
    public void writeToConfig(byte[] bs, String dtsIp, String fileName) {
        try {
            File f = getIniFileByIp(dtsIp, fileName);
            if (f.exists()) {
                FileWriter fileWriter = new FileWriter(f);
                fileWriter.write("");
                fileWriter.flush();
                fileWriter.close();
            }
            OutputStream oStream = new FileOutputStream(f);
            oStream.write(bs);
            oStream.close();
            log.info("INI写入完成，本地文件名:" + f.getCanonicalPath());
        } catch (IOException exception) {
            log.error(exception.toString());
        }
    }

    /**
     * 从dts的配置文件读取ini文件
     *
     * @param dtsIp dts的ip
     * @return 读取到的map
     */
    public Map<String, Object> getGlobalConfig(String dtsIp) {
        Map<String, Object> map = new HashMap<>(8);
        BufferedReader br = null;
        try {
            File f = getIniFileByIp(dtsIp, "");
            if (!f.exists()) {
                throw new CMSException("文件不存在");
            }
            // FileInputStream inputStream = new FileInputStream(f);
            br = new BufferedReader(new FileReader(f));
            String line;

            String sep = "     ";
            while ((line = br.readLine()) != null) {
                if (StringUtils.isBlank(line))
                    break;
                if (line.contains("Global"))
                    continue;
                String key = line.split(sep)[0];
                String val = line.split(sep)[1];
                map.put(key, val);
            }
        } catch (IOException e) {
            log.error("ini文件读取异常：" + dtsIp);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return map;
    }

    /**
     * 将map读内容写入到ini
     *
     * @param map   需要写入的参数map
     * @param dtsIp dts的ip地址
     */
    public String setGlobalConfig(Map<String, Object> map, String dtsIp) {
        BufferedReader br = null;
        try {
            File f = getIniFileByIp(dtsIp, "");
            br = new BufferedReader(new FileReader(f));
            String line;
            String sep = "     ";
            StringBuilder buf = new StringBuilder();
            Set<String> keySet = map.keySet();
            boolean inGlobal = false;
            while ((line = br.readLine()) != null) {
                // 读到空白行就跳出
                if (StringUtils.isBlank(line)) {
                    inGlobal = false;
                    buf.append("\n");
                    continue;
                }
                if (line.contains("Global")) {
                    inGlobal = true;
                }

                // 包含key 则覆盖该行
                String key;
                if (inGlobal && keySet.contains(key = line.split(sep)[0])) {
                    String newLine = key + sep + map.get(key);
                    buf.append(newLine).append("\n");
                } else {
                    buf.append(line).append("\n");
                }
            }
            return buf.toString();
        } catch (IOException ex) {
            log.error("组包出错：" + dtsIp);
            return "";
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 根据ip和通道号获取指定通道的配置信息
     *
     * @param dtsIp   dts设备的ip
     * @param channel 通道
     * @return 配置的map
     */
    public Map<String, Object> getChannelConfig(String dtsIp, int channel) {
        Map<String, Object> map = new LinkedHashMap<>(8);
        Map<String, String> basicMap = new LinkedHashMap<>(8);
        List<String> insplaceList = new ArrayList<>();
        List<String> revisecoefList = new ArrayList<>();
        List<String> connectList = new ArrayList<>();
        map.put("basic", basicMap);
        map.put("insplace", insplaceList);
        map.put("revisecoef", revisecoefList);
        map.put("connect", connectList);
        BufferedReader br = null;
        try {
            File f = getIniFileByIp(dtsIp, "");
            if (!f.exists()) {
                throw new CMSException("文件不存在");
            }
            br = new BufferedReader(new FileReader(f));
            String line, sec = "", ch = "Ch" + channel, sep = "     ";
            while ((line = br.readLine()) != null) {
                if (line.contains(ch + "_basic")) {
                    sec = "basic";
                    continue;
                }
                if (line.contains(ch + "_insplace")) {
                    sec = "insplace";
                    continue;
                }
                if (line.contains(ch + "_revisecoef")) {
                    sec = "revisecoef";
                    continue;
                }
                if (line.contains(ch + "_connect")) {
                    sec = "connect";
                    continue;
                }
                if (StringUtils.isBlank(line) && sec.length() > 0) {
                    // 读到ch的空行,如果是connect 则不读了
                    if (sec.equals("connect"))
                        break;
                    continue;
                }
                switch (sec) {
                    case "basic":
                        final String[] conf = line.split(sep);
                        basicMap.put(conf[0], conf[1]);
                        break;
                    case "insplace":
                        insplaceList.add(line);
                        break;
                    case "revisecoef":
                        revisecoefList.add(line.replace(sep, ","));
                        break;
                    case "connect":
                        connectList.add(line);
                        break;
                    default:
                        break;
                }

            }
        } catch (IOException e) {
            log.error(e.toString());
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return map;
    }

    public String setChannelConfig(JSONObject json, String dtsIp, Integer channel) {
        BufferedReader br = null;
        try {
            String ch = "Ch" + channel;
            File f = getIniFileByIp(dtsIp, "");
            br = new BufferedReader(new FileReader(f));
            boolean inChSec = false;
            ;
            String sep = "     ", sec = "", line;
            StringBuilder buf = new StringBuilder();
            JSONObject basic = json.getJSONObject("basic");

            // boolean inChBasic = false,insplace = false,revisecoef = false,connect =
            // false;

            while ((line = br.readLine()) != null) {
                if (line.contains(ch + "_basic")) {
                    buf.append(line).append("\n");
                    sec = "basic";
                    inChSec = true;
                }
                if (line.contains(ch + "_insplace")) {
                    buf.append(line).append("\n");
                    sec = "insplace";
                }
                if (line.contains(ch + "_revisecoef")) {
                    buf.append(line).append("\n");
                    sec = "revisecoef";
                }
                if (line.contains(ch + "_connect")) {
                    buf.append(line).append("\n");
                    sec = "connect";
                }

                if (sec.length() > 0) {
                    if (StringUtils.isBlank(line)) {
                        // 读connect下面的空行 则不写了
                        buf.append("\n");
                        continue;
                    }
                }

                switch (sec) {
                    case "basic":
                        basic.forEach((key, value) -> {
                            String newLine = key + sep + value;
                            buf.append(newLine).append("\n");
                        });
                        sec = "";
                        break;
                    case "insplace":
                        String[] ins = json.getObject("insplace", String[].class);
                        for (String in : ins) {
                            buf.append(in).append("\n");
                        }
                        sec = "";
                        break;
                    case "revisecoef":
                        String[] rev = json.getObject("revisecoef", String[].class);
                        for (String in : rev) {
                            buf.append(in.replace(",", sep)).append("\n");
                        }
                        sec = "";
                        break;
                    case "connect":
                        String[] con = json.getObject("connect", String[].class);
                        for (String in : con) {
                            buf.append(in).append("\n");
                        }
                        sec = "";
                        inChSec = false;
                        break;
                    default:
                        if (!inChSec) {
                            buf.append(line).append("\n");
                        } else if (StringUtils.isBlank(line)) {
                            buf.append("\n");
                        }
                        break;
                }

            }
            return buf.toString();
        } catch (IOException ex) {
            log.error("组包出错：" + dtsIp);
            return "";
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 根据ip和文件名获取文件路径
     *
     * @param dtsIp    ip地址
     * @param fileName 文件名 ，空文件名则以ip作为文件名
     * @return 指定config.txt文件
     * @throws IOException io异常
     */
    private File getIniFileByIp(String dtsIp, String fileName) throws IOException {
        String localFileName;
        if (StringUtils.isBlank(fileName)) {
            localFileName = dtsIp.replace(".", "-") + ".txt";
        } else {
            localFileName = dtsIp.replace(".", "-") + "-" + fileName + ".txt";
        }

        File path = new File(Constant.EXPORTPATH + Constant.DTSConfigPath);
        if (!path.exists()) {
            if (!path.mkdir()) {
                throw new IOException("目录创建失败:" + path);
            }
        }
        return new File(path.getAbsolutePath(), localFileName);
    }

}
